<script lang="ts" setup name="ImagesUpload">
import type { UploadProps } from 'element-plus'
import { ElMessage } from 'element-plus'
const props = defineProps({
  action: {
    type: String,
    default: import.meta.env.VITE_APP_UPLOAD_URL
  },
  headers: {
    type: Object,
    default: () => {}
  },
  data: {
    type: Object,
    default: () => {}
  },
  name: {
    type: String,
    default: 'file'
  },
  url: {
    type: Array,
    default: () => []
  },
  max: {
    type: Number,
    default: 3
  },
  size: {
    type: Number,
    default: 2
  },
  width: {
    type: Number,
    default: 150
  },
  height: {
    type: Number,
    default: 150
  },
  placeholder: {
    type: String,
    default: ''
  },
  notip: {
    type: Boolean,
    default: false
  },
  ext: {
    type: Array,
    default: () => ['jpg', 'png', 'gif', 'bmp']
  }
})
const emit = defineEmits(['update:url', 'onSuccess'])
const { setFileUrl } = useHttpUrl()
const priviewUrl: any = ref([])
watch(
  () => props.url,
  val => {
    if (val) {
      priviewUrl.value = val.map((it: any) => {
        return setFileUrl(it)
      })
    }
  },
  { deep: true }
)

const uploadData = ref({
  dialogImageIndex: 0,
  imageViewerVisible: false,
  progress: {
    preview: '',
    percent: 0
  }
})

// 预览
function preview(index: number) {
  uploadData.value.dialogImageIndex = index
  uploadData.value.imageViewerVisible = true
}
// 关闭预览
function previewClose() {
  uploadData.value.imageViewerVisible = false
}
// 移除
function remove(index: number) {
  const url = props.url
  url.splice(index, 1)
  emit('update:url', url)
}
// 移动
function move(index: number, type: 'left' | 'right') {
  const url = props.url
  if (type === 'left' && index !== 0)
    url[index] = url.splice(index - 1, 1, url[index])[0]

  if (type === 'right' && index !== url.length - 1)
    url[index] = url.splice(index + 1, 1, url[index])[0]

  emit('update:url', url)
}

const beforeUpload: UploadProps['beforeUpload'] = (file: any) => {
  const fileName = file.name.split('.')
  const fileExt = fileName.at(-1)
  const isTypeOk = props.ext.includes(fileExt)
  const isSizeOk = file.size / 1024 / 1024 < props.size
  if (!isTypeOk)
    ElMessage.error(`上传图片只支持 ${props.ext.join(' / ')} 格式！`)

  if (!isSizeOk)
    ElMessage.error(`上传图片大小不能超过 ${props.size}MB！`)

  if (isTypeOk && isSizeOk)
    uploadData.value.progress.preview = URL.createObjectURL(file)

  return isTypeOk && isSizeOk
}
const onProgress: UploadProps['onProgress'] = (file: { percent: number; }) => {
  uploadData.value.progress.percent = ~~file.percent
}
const onSuccess: UploadProps['onSuccess'] = (res: { data: { id: unknown; }; }) => {
  uploadData.value.progress.preview = ''
  uploadData.value.progress.percent = 0
  emit(
    'update:url',
    props.url?.length === 0
      ? [res?.data?.id]
      : props.url?.length
        ? props.url.concat([res?.data?.id])
        : []
  )
  emit('onSuccess', res)
}
</script>

<template>
  <div class="upload-container">
    <div v-for="(item, index) in (url as string[])" :key="index" class="images">
      <el-image
        v-if="index < max"
        :src="setFileUrl(item)"
        :style="`width:${width}px;height:${height}px;`"
        fit="cover"
      />
      <div class="mask">
        <div class="actions">
          <span title="预览" @click="preview(index)">
            <IkSvgIcon name="iksvg_yulan" />
          </span>
          <span title="移除" @click="remove(index)">
            <IkSvgIcon name="iksvg_guanbi-yemianbiaoqian" />
          </span>
          <span
            v-show="url.length > 1"
            title="左移"
            :class="{ disabled: index === 0 }"
            @click="move(index, 'left')"
          >
            <IkSvgIcon name="iksvg_fanhui" />
          </span>
          <span
            v-show="url.length > 1"
            title="右移"
            :class="{ disabled: index === url.length - 1 }"
            @click="move(index, 'right')"
          >
            <IkSvgIcon name="iksvg_youyi" />
          </span>
        </div>
      </div>
    </div>
    <el-upload
      v-show="url.length < max"
      :show-file-list="false"
      :headers="headers"
      :action="action"
      :data="data"
      :name="name"
      :before-upload="beforeUpload"
      :on-progress="onProgress"
      :on-success="onSuccess"
      drag
      class="images-upload"
    >
      <div class="image-slot" :style="`width:${width}px;height:${height}px;`">
        <el-icon>
          <IkSvgIcon name="iksvg_xinzeng" />
        </el-icon>
      </div>
      <div
        v-show="uploadData.progress.percent"
        class="progress"
        :style="`width:${width}px;height:${height}px;`"
      >
        <el-image
          :src="uploadData.progress.preview"
          :style="`width:${width}px;height:${height}px;`"
          fit="fill"
        />
        <el-progress
          type="circle"
          :width="Math.min(width, height) * 0.8"
          :percentage="uploadData.progress.percent"
        />
      </div>
    </el-upload>
    <div v-if="!notip" class="el-upload__tip">
      <div style="display: inline-block">
        <el-alert
          :title="`上传图片支持 ${ext.join(
            ' / ',
          )} 格式，单张图片大小不超过 ${size}MB，建议图片尺寸为 ${width}*${height}，且图片数量不超过 ${max} 张`"
          type="info"
          show-icon
          :closable="false"
        />
      </div>
    </div>
    <el-image-viewer
      v-if="uploadData.imageViewerVisible"
      :url-list="priviewUrl"
      :initial-index="uploadData.dialogImageIndex"
      teleported
      @close="previewClose"
    />
  </div>
</template>

<style lang="scss" scoped>
.upload-container {
  line-height: initial;
}

.el-image {
  display: block;
}

.images {
  position: relative;
  display: inline-block;
  margin-right: 10px;
  border: 1px dashed var(--el-border-color);
  border-radius: 6px;
  overflow: hidden;

  .mask {
    opacity: 0;
    position: absolute;
    top: 0;
    width: 100%;
    height: 100%;
    background-color: var(--el-overlay-color-lighter);
    transition: opacity 0.3s;

    .actions {
      width: 100px;
      height: 100px;
      display: flex;
      flex-wrap: wrap;
      align-items: center;
      justify-content: center;

      @include position-center(xy);

      span {
        width: 50%;
        text-align: center;
        cursor: pointer;
        color: var(--el-color-white);
        transition: color 0.1s, transform 0.1s;

        &.disabled {
          color: var(--el-text-color-disabled);
          cursor: not-allowed;
        }

        &:hover:not(.disabled) {
          transform: scale(1.5);
        }

        .el-icon {
          font-size: 24px;
        }
      }
    }
  }

  &:hover .mask {
    opacity: 1;
  }
}

.images-upload {
  display: inline-block;
  vertical-align: top;
}

:deep(.el-upload) {
  .el-upload-dragger {
    display: inline-block;
    padding: 0;

    &.is-dragover {
      border-width: 1px;
    }

    .image-slot {
      display: flex;
      justify-content: center;
      align-items: center;
      width: 100%;
      height: 100%;
      color: var(--el-text-color-placeholder);
      background-color: transparent;

      i {
        font-size: 30px;
      }
    }

    .progress {
      position: absolute;
      top: 0;

      &::after {
        content: '';
        position: absolute;
        width: 100%;
        height: 100%;
        left: 0;
        top: 0;
        background-color: var(--el-overlay-color-lighter);
      }

      .el-progress {
        z-index: 1;

        @include position-center(xy);

        .el-progress__text {
          color: var(--el-text-color-placeholder);
        }
      }
    }
  }
}
</style>
